<template>
  <el-dialog v-model="dialogVisible" width="600" :title="title" draggable appendToBody destroyOnClose lockScroll :closeOnClickModal="false">
    <el-form ref="elFormRef" v-loading="initLoading" style="margin-top: 10px" scrollToError statusIcon :model="formData" :rules="rules">
      <div>
        <!-- 用于防止密码自动填充 -->
        <input style="position: absolute; top: -1vh; left: -1vw; z-index: -1; width: 0; height: 0; padding: 0" />
        <input type="password" style="position: absolute; position: absolute; top: -1vh; left: -1vw; z-index: -1; width: 0; height: 0; padding: 0" />
      </div>
      <div style="display: flex; justify-content: center; width: 100%">
        <div style="display: flex; flex-direction: column; align-items: center; justify-content: flex-start; width: 120px">
          <el-form-item label="" prop="avatar">
            <rest-upload-qn
              v-model="formData.avatar"
              folder="personal/avatar"
              :width="120"
              :height="120"
              :accept="['.png', '.jpg', '.svg', '.webp']"
              :limit="1"
              :afterSelectFile="openCropper"
            ></rest-upload-qn>
          </el-form-item>
          <span style="font-size: 12px; color: var(--el-text-color-regular)">头像</span>
        </div>
        <div style="flex: 1; max-width: 580px; margin-left: 30px">
          <el-form-item label="账号" labelWidth="6em" prop="username">
            <el-input v-model="formData.username" :maxlength="usernameMax" placeholder="请输入账号" clearable></el-input>
          </el-form-item>
          <el-form-item label="密码" labelWidth="6em" prop="password">
            <el-input
              v-model="formData.password"
              type="password"
              :showPassword="action === 'add'"
              :maxlength="passwordMax"
              :placeholder="action === 'add' ? '请输入密码' : '请输入新密码 (为空代表不修改密码)'"
              clearable
            ></el-input>
          </el-form-item>
          <el-form-item label="电话" labelWidth="6em" prop="phone">
            <el-input
              v-model="formData.phone"
              maxlength="11"
              :formatter="(val: string) => val.replace(/[^\d]/, '')"
              :parser="(val: string) => val.replace(/[^\d]/, '')"
              placeholder="请输入电话"
              clearable
            ></el-input>
          </el-form-item>
          <el-form-item label="真实姓名" labelWidth="6em" prop="realname">
            <el-input v-model="formData.realname" :maxlength="realnameMax" placeholder="请输入真实姓名" clearable></el-input>
          </el-form-item>
          <el-form-item label="性别" labelWidth="6em" prop="sex" style="flex: 2; min-width: 180px">
            <el-radio-group v-model="formData.sex">
              <el-radio label="男" :value="1"></el-radio>
              <el-radio label="女" :value="2"></el-radio>
            </el-radio-group>
          </el-form-item>
          <el-form-item label="部门" labelWidth="6em" prop="deptId">
            <el-tree-select
              v-model="formData.deptId"
              :data="deptTree"
              :props="{
                label: 'deptName',
                children: 'childrenDeptList',
              }"
              valueKey="deptId"
              checkStrictly
              :renderAfterExpand="false"
              showCheckbox
            ></el-tree-select>
          </el-form-item>
          <el-form-item label="角色" labelWidth="6em" prop="roleId" style="flex: 2; min-width: 180px">
            <bubble-select-local
              v-if="!isAdmin"
              :modelValue="{ roleName: formData.roleName, roleId: formData.roleId }"
              labelKey="roleName"
              valueKey="roleId"
              style="width: 100%"
              returnOriginal
              :axios="getAllRoleAxios"
              placeholder="请选择角色"
              @change="roleChange"
            ></bubble-select-local>
            <el-select v-else :modelValue="formData.roleName" disabled placeholder="请选择角色" clearable>
              <el-option :label="formData.roleName" :value="formData.roleName"></el-option>
            </el-select>
          </el-form-item>
          <el-form-item labelWidth="6em">
            <div style="width: 100%; padding-top: 20px">
              <el-button style="width: 100%" type="success" :loading="submitLoading" :disabled="submitLoading" :icon="IconPlus" @click="submit">
                {{ action === 'add' ? '提交' : '保存修改' }}
              </el-button>
            </div>
          </el-form-item>
        </div>
      </div>
    </el-form>
    <rest-image-cropper ref="restImageCropperRef"></rest-image-cropper>
  </el-dialog>
</template>

<script setup lang="ts">
  import IconPlus from '~icons/ep/plus';
  import {
    type AddAdminUser,
    type AdminUser,
    type DeptItemTree,
    addAdminUserAxios,
    editAdminUserAxios,
    getAllRoleAxios,
    getSysDeptTreeAxios,
  } from '@/api/permission-management';
  import type { FormInstance, FormRules } from 'element-plus';
  import { getPasswordRules, getPhoneRules, getUsernameRules } from '@/utils/page/rules';
  const restImageCropperRef: $RefComp<'RestImageCropper'> = ref(null);

  type $AddShowData = {
    type: 'add';
    /** 添加时的回调 */
    addCallBack: () => void;
  };
  type $EditShowData = {
    type: 'edit';
    /** 管理员 */
    adminUser: AdminUser;
    /** 编辑时的回调 */
    editCallBack: () => void;
  };

  let addCallBack: $AddShowData['addCallBack'] | undefined = undefined;
  let editCallBack: $EditShowData['editCallBack'] | undefined = undefined;
  const submitLoading = ref(false);
  const dialogVisible = ref(false);
  const elFormRef: Ref<FormInstance | null> = ref(null);
  const title: Ref<string> = ref('');
  const isAdmin = ref(false);
  const initLoading = ref(false);
  const deptTree = ref<DeptItemTree[]>([]);

  const formData: AddAdminUser = reactive<AddAdminUser>({
    userId: undefined,
    avatar: '',
    phone: '',
    realname: '',
    sex: 1,
    password: randomPassword(),
    roleId: '',
    roleName: '',
    username: '',
    deptId: null,
  });

  const action = ref<'add' | 'edit'>('add');

  const realnameMin = 2;
  const realnameMax = 36;
  const { passwordMax, passwordRules } = getPasswordRules();
  const { phoneRules } = getPhoneRules();
  const { usernameRules, usernameMax } = getUsernameRules();
  const rules = computed<FormRules>(() => {
    const _rules: FormRules = {
      phone: phoneRules,
      username: usernameRules,
      realname: [
        { required: true, type: 'string', message: '请输入真实姓名', trigger: ['blur', 'change'] },
        { min: realnameMin, max: realnameMax, type: 'string', message: `真实姓名长度在 ${realnameMin} 到 ${realnameMax} 之间`, trigger: ['blur', 'change'] },
      ],
      sex: [
        { required: true, type: 'number', message: '请选择性别', trigger: ['blur', 'change'] },
        { min: 1, max: 2, type: 'number', message: `性别不合法`, trigger: ['blur', 'change'] },
      ],
      deptId: [{ required: true, type: 'number', message: '请选择部门', trigger: ['blur', 'change'] }],
    };

    if (action.value === 'add') {
      _rules.password = passwordRules('密码');
    }

    if (!isAdmin.value) {
      _rules.roleId = [{ required: true, type: 'number', message: '请选择角色', trigger: ['blur', 'change'] }];
    }

    return _rules;
  });

  /**
   * 显示
   */
  async function show(data: $AddShowData | $EditShowData) {
    console.log(data);

    title.value = data.type === 'edit' ? '编辑管理员' : '新增管理员';
    action.value = data.type;
    isAdmin.value = data.type === 'edit' && typeof data.adminUser.admin === 'boolean' ? data.adminUser.admin : false;
    formData.avatar = data.type === 'edit' && data.adminUser.avatar ? data.adminUser.avatar : '';
    formData.phone = data.type === 'edit' && data.adminUser.phone ? data.adminUser.phone : '';
    formData.realname = data.type === 'edit' && data.adminUser.realname ? data.adminUser.realname : '';
    formData.sex = data.type === 'edit' && !isNaN(data.adminUser.sex) ? data.adminUser.sex : 0;
    formData.password = '';
    formData.roleId = data.type === 'edit' && data.adminUser.roleId ? data.adminUser.roleId : '';
    formData.roleName = data.type === 'edit' && data.adminUser.roleName ? data.adminUser.roleName : '';
    formData.username = data.type === 'edit' && data.adminUser.username ? data.adminUser.username : '';
    formData.deptId = data.type === 'edit' && data.adminUser.deptId ? data.adminUser.deptId : null;
    formData.userId = data.type === 'edit' && data.adminUser.userId ? data.adminUser.userId : undefined;
    editCallBack = 'editCallBack' in data && typeof data.editCallBack === 'function' ? data.editCallBack : undefined;
    addCallBack = 'addCallBack' in data && typeof data.addCallBack === 'function' ? data.addCallBack : undefined;
    dialogVisible.value = true;

    try {
      initLoading.value = true;
      const res = await getSysDeptTreeAxios();
      deptTree.value = res.data;
      initLoading.value = false;
    } catch (error) {
      initLoading.value = false;
      ElToast.error(error.msg || '获取部门信息失败');
    }
  }

  /**
   * 隐藏
   */
  function hide() {
    dialogVisible.value = false;
  }

  /** 角色修改 */
  function roleChange(data: { roleId: number | ''; roleName: string }) {
    formData.roleName = data.roleName;
    formData.roleId = data.roleId;
  }

  /** 提交 */
  async function submit() {
    try {
      await elFormRef.value?.validate();
      try {
        submitLoading.value = true;
        if (action.value === 'edit') {
          // 修改
          await editAdminUserAxios({ ...formData });
          typeof editCallBack === 'function' && editCallBack();
          ElToast.success('修改成功');
        } else if (action.value === 'add') {
          // 新增
          const res = await addAdminUserAxios(formData);
          formData.password = '';
          action.value = 'edit';
          formData.userId = res.data;
          ElToast.success('新增成功');
          typeof addCallBack === 'function' && addCallBack();
        }
        hide();
        submitLoading.value = false;
      } catch (error) {
        submitLoading.value = false;
        ElToast.error(error.msg || '提交失败，-BD003');
      }
    } catch (error) {
      ElToast.error('提交失败，请完善表单，-BD002');
    }
  }

  /** 打开裁剪框 */
  function openCropper(files: File[]): Promise<File[]> {
    return new Promise((resolve, reject) => {
      const file = files[0];
      if (file) {
        restImageCropperRef.value?.show({
          file,
          croppedCanvasOptions: {
            fillColor: '#ffffff',
            maxWidth: 240,
            maxHeight: 240,
          },
          fail: () => {
            reject(null);
          },
          success: (res: File) => {
            resolve([res] as File[]);
          },
        });
      } else {
        resolve(files);
      }
    });
  }

  /** 随机密码 */
  function randomPassword() {
    return (Math.random().toString(36).slice(2) + Math.random().toString(36).toUpperCase().slice(2)).slice(0, 18);
  }
  defineExpose({ show, hide });
</script>
